package com.piece.core.web.filter;

import com.piece.core.framework.constant.ApplicationConstants;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.properties.ApplicationProperties;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Xss 过滤器
 */
@Slf4j
@Component
public class XssRequestFilter implements FilterHook {

    @Autowired
    private ApplicationProperties applicationProperties;

    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    private List<String> excludes = new ArrayList<>();
    private String[] illegalParam;

    @Override
    public String[] getFilterPath() {
        return null;
    }

    @Override
    public Integer getIndex() {
        return Integer.MIN_VALUE;
    }

    @Override
    public void initFilter() {
        String customExcludes = applicationProperties.getValue(ApplicationConstants.XSS_EXCLUDE_URL);
        if (StringUtil.isNotEmpty(customExcludes)) {
            this.setExcludes(Arrays.asList(customExcludes.split(",")));
            this.setIllegalParam(Convert.toStrArray(applicationProperties.getValue(ApplicationConstants.XSS_ILLEGAL_PARAM)));
        }
    }

    @Override
    public Pair beforeFilter(HttpServletRequest request, HttpServletResponse response) {
        try {
            if (shouldNotFilter(request)) {
                return Pair.of(request, response);
            }
        } catch (ServletException e) {
            throw new ServerException(e.getMessage());
        }
        return Pair.of(new XssRequestWrapper(request, this.illegalParam), response);
    }

    @Override
    public void afterFilter(HttpServletRequest request, HttpServletResponse response) {
    }

    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        return this.excludes.stream().anyMatch(exclude -> pathMatcher.match(exclude, request.getRequestURI()));
    }

    public void setExcludes(List<String> excludes) {
        this.excludes.clear();
        this.excludes.addAll(excludes);
        this.excludes.add("/" + applicationProperties.getUpload() + "/**");
    }

    public void setIllegalParam(String[] illegalParam) {
        this.illegalParam = illegalParam;
    }
}
